bitkeeper revision 1.131 (3e7270ecL24hQl_PjDBYoS8hhB8GTA)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sat, 15 Mar 2003 00:16:44 +0000 (00:16 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Sat, 15 Mar 2003 00:16:44 +0000 (00:16 +0000)
multicall.h:
  new file
Many files:
  Multicall now available, so that Xen syscalls can be batched to amortise cost of trap to ring 0. Used by xenolinux to reduce the cost of a context switch.

14 files changed:
.rootkeys
xen/arch/i386/entry.S
xen/arch/i386/mm.c
xen/common/kernel.c
xen/common/schedule.c
xen/include/hypervisor-ifs/hypervisor-if.h
xen/include/xeno/config.h
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/hypervisor.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h [new file with mode: 0644]

index c0f10798ab6de3572c8b94c8eb2fd1512b0ed1c6..e1f67d7c3f4543eef2160df28fb668df58be9295 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3e5a4e673p7PEOyHFm3nHkYX6HQYBg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/irq.h
 3e5a4e67zoNch27qYhEBpr2k6SABOg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu.h
 3e5a4e678ddsQOpbSiRdy1GRcDc9WA xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h
+3e7270deQqtGPSnFxcW4AvJZuTUWfg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h
 3e5a4e67mnQfh-R8KcQCaVo2Oho6yg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/page.h
 3e5a4e67uTYU5oEnIDjxuaez8njjqg xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h
 3e5a4e67X7JyupgdYkgDX19Huj2sAw xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable-2level.h
index cd4957816884092e6d0d84983db4e72cf24b2279..436d12a8ff2190644da6f4a32f70041716a61826 100644 (file)
@@ -79,6 +79,8 @@
  */
 
 #include <xeno/config.h>
+#include <xeno/errno.h>
+#include <hypervisor-ifs/hypervisor-if.h>
 #include <asm/smp.h>
 
 EBX            = 0x00
@@ -183,6 +185,77 @@ ENTRY(ret_from_newdomain)
        GET_CURRENT(%ebx)
        jmp test_all_events
 
+        ALIGN
+/*
+ * HYPERVISOR_multicall(call_list, nr_calls)
+ *   Execute a list of 'nr_calls' system calls, pointed at by 'call_list'.
+ *   This is fairly easy except that:
+ *   1. We may fault reading the call list, and must patch that up; and
+ *   2. We cannot recursively call HYPERVISOR_multicall, or a malicious
+ *      caller could cause our stack to blow up.
+ */
+stringstring:
+        .asciz "%08x %08x %08x %08x %08x %08x %d\n"
+do_multicall:
+        popl  %eax
+        cmpl  $SYMBOL_NAME(ret_from_hypervisor_call),%eax
+        jne   multicall_exit /* bail if called recursively */
+        pushl %ebx
+        movl  4(%esp),%ebx   /* EBX == call_list */
+        movl  8(%esp),%ecx   /* ECX == nr_calls  */
+multicall_loop:
+        pushl %ecx
+multicall_fault1: 
+        pushl 20(%ebx)
+multicall_fault2: 
+        pushl 16(%ebx)
+multicall_fault3: 
+        pushl 12(%ebx)
+multicall_fault4: 
+        pushl 8(%ebx)
+multicall_fault5: 
+        pushl 4(%ebx)
+multicall_fault6: 
+        movl  (%ebx),%eax
+        andl  $255,%eax
+        call  *SYMBOL_NAME(hypervisor_call_table)(,%eax,4)
+        addl  $20,%esp
+        popl  %ecx
+        addl  $BYTES_PER_MULTICALL_ENTRY,%ebx
+        loop  multicall_loop
+        popl  %ebx
+multicall_exit:
+        xorl  %eax,%eax
+        jmp   ret_from_hypervisor_call
+
+.section __ex_table,"a"
+        .align 4
+        .long multicall_fault1, multicall_fixup1
+        .long multicall_fault2, multicall_fixup2
+        .long multicall_fault3, multicall_fixup3
+        .long multicall_fault4, multicall_fixup4
+        .long multicall_fault5, multicall_fixup5
+        .long multicall_fault6, multicall_fixup6
+.previous
+               
+.section .fixup,"ax"
+multicall_fixup6: 
+        addl  $4,%esp
+multicall_fixup5: 
+        addl  $4,%esp
+multicall_fixup4: 
+        addl  $4,%esp
+multicall_fixup3: 
+        addl  $4,%esp
+multicall_fixup2: 
+        addl  $4,%esp
+multicall_fixup1:
+        addl  $4,%esp
+        popl  %ebx
+        movl  $-EFAULT,%eax
+        jmp   ret_from_hypervisor_call
+.previous        
+                
         ALIGN
 restore_all:
        RESTORE_ALL
@@ -194,7 +267,9 @@ ENTRY(hypervisor_call)
        GET_CURRENT(%ebx)
        andl $255,%eax
        call *SYMBOL_NAME(hypervisor_call_table)(,%eax,4)
-       movl %eax,EAX(%esp)             # save the return value
+
+ret_from_hypervisor_call:
+        movl %eax,EAX(%esp)            # save the return value
 
 test_all_events:
         mov  PROCESSOR(%ebx),%eax
@@ -517,10 +592,11 @@ ENTRY(hypervisor_call_table)
         .long SYMBOL_NAME(do_process_page_updates)
         .long SYMBOL_NAME(do_console_write)
         .long SYMBOL_NAME(do_set_gdt)
-        .long SYMBOL_NAME(do_stack_and_ldt_switch)
+        .long SYMBOL_NAME(do_stack_switch)
+        .long SYMBOL_NAME(do_ldt_switch)
         .long SYMBOL_NAME(do_net_update)
         .long SYMBOL_NAME(do_fpu_taskswitch)
-        .long SYMBOL_NAME(do_sched_op)
+        .long SYMBOL_NAME(do_yield)
         .long SYMBOL_NAME(kill_domain)
         .long SYMBOL_NAME(do_dom0_op)
         .long SYMBOL_NAME(do_network_op)
@@ -530,6 +606,7 @@ ENTRY(hypervisor_call_table)
         .long SYMBOL_NAME(do_update_descriptor)
         .long SYMBOL_NAME(do_set_fast_trap)
         .long SYMBOL_NAME(do_dom_mem_op)
-        .rept NR_syscalls-(.-hypervisor_call_table)/4
+        .long SYMBOL_NAME(do_multicall)
+        .rept NR_syscalls-((.-hypervisor_call_table)/4)
         .long SYMBOL_NAME(sys_ni_syscall)
        .endr
index 2d4d8ddf5206743c6f337caf7e7efd72b7d9e026..e330c092c6deddfe70c5bb9339cdc1b297b48caa 100644 (file)
@@ -97,8 +97,7 @@ void __init zap_low_mappings (void)
 }
 
 
-long do_stack_and_ldt_switch(
-    unsigned long ss, unsigned long esp, unsigned long ldts)
+long do_stack_switch(unsigned long ss, unsigned long esp)
 {
     int nr = smp_processor_id();
     struct tss_struct *t = &init_tss[nr];
@@ -106,19 +105,6 @@ long do_stack_and_ldt_switch(
     if ( (ss == __HYPERVISOR_CS) || (ss == __HYPERVISOR_DS) )
         return -1;
 
-    if ( ldts != current->mm.ldt_sel )
-    {
-        unsigned long *ptabent;
-        ptabent = (unsigned long *)GET_GDT_ADDRESS(current);
-        /* Out of range for GDT table? */
-        if ( (ldts * 8) > GET_GDT_ENTRIES(current) ) return -1;
-        ptabent += ldts * 2; /* 8 bytes per desc == 2 * unsigned long */
-        /* Not an LDT entry? (S=0b, type =0010b) */
-        if ( (*ptabent & 0x00001f00) != 0x00000200 ) return -1;
-        current->mm.ldt_sel = ldts;
-        __load_LDT(ldts);
-    }
-
     current->thread.ss1  = ss;
     current->thread.esp1 = esp;
     t->ss1  = ss;
@@ -128,6 +114,23 @@ long do_stack_and_ldt_switch(
 }
 
 
+long do_ldt_switch(unsigned long ldts)
+{
+    unsigned long *ptabent;
+
+    ptabent = (unsigned long *)GET_GDT_ADDRESS(current);
+    /* Out of range for GDT table? */
+    if ( (ldts * 8) > GET_GDT_ENTRIES(current) ) return -1;
+    ptabent += ldts * 2; /* 8 bytes per desc == 2 * unsigned long */
+    /* Not an LDT entry? (S=0b, type =0010b) */
+    if ( ldts && ((*ptabent & 0x00001f00) != 0x00000200) ) return -1;
+    current->mm.ldt_sel = ldts;
+    __load_LDT(ldts);
+
+    return 0;
+}
+
+
 long do_set_gdt(unsigned long *frame_list, int entries)
 {
     return -ENOSYS;
index 28eaae9b51196918f8f3d2c537ed08e4f1b01574..0e4552fe117c2d6648fde17bf63ab01267d46e30 100644 (file)
@@ -533,7 +533,7 @@ int console_export(char *str, int len)
 }
 
 
-long do_console_write(char *str, int count)
+long do_console_write(char *str, unsigned int count)
 {
 #define SIZEOF_BUF 256
     unsigned char safe_str[SIZEOF_BUF];
index 92bade958f206fc67dd3b163d74964f8594e86e3..3ef29e3c5cb24dd764e7b159d4159ac75b91364b 100644 (file)
@@ -148,12 +148,10 @@ int wake_up(struct task_struct *p)
 }
 
 /****************************************************************************
- * Domain requested scheduling operations
- * KAF: turn it back into do_yield()!
+ * Voluntarily yield the processor to another domain, until an event occurs.
  ****************************************************************************/
-long do_sched_op(void)
+long do_yield(void)
 {
-    /* XXX implement proper */
     current->state = TASK_INTERRUPTIBLE;
     schedule();
     return 0;
@@ -519,7 +517,7 @@ void schedulers_start(void)
  * Schedule timeout is used at a number of places and is a bit meaningless 
  * in the context of Xen, as Domains are not able to call these and all 
  * there entry points into Xen should be asynchronous. If a domain wishes
- * to block for a while it should use Xen's sched_op entry point.
+ * to block for a while it should use Xen's sched_op/yield entry point.
  ****************************************************************************/
 
 static void process_timeout(unsigned long __data)
index 31cc8b18d8a697cad47a70adb9bc132752ccb393..797605e9c1972c70a866e55ab786844dd8dcfdc8 100644 (file)
  * Interface to Xeno hypervisor.
  */
 
-#include "network.h"
-#include "block.h"
-
 #ifndef __HYPERVISOR_IF_H__
 #define __HYPERVISOR_IF_H__
 
 /*
- * Virtual addresses beyond this are not modifiable by guest OSes.
- * The machine->physical mapping table starts at this address, read-only
- * to all domains except DOM0.
+ * SEGMENT DESCRIPTOR TABLES
  */
-#define HYPERVISOR_VIRT_START (0xFC000000UL)
-#ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
-#endif
-
-typedef struct trap_info_st
-{
-    unsigned char  vector;  /* exception/interrupt vector */
-    unsigned char  dpl;     /* privilege level            */
-    unsigned short cs;      /* code selector              */
-    unsigned long  address; /* code address               */
-} trap_info_t;
-
-
-typedef struct
-{
-/*
- * PGREQ_XXX: specified in least-significant bits of 'ptr' field.
- * All requests specify relevent PTE or PT address in 'ptr'.
- * Normal requests specify update value in 'value'.
- * Extended requests specify command in least 8 bits of 'value'.
- */
-/* A normal page-table update request. */
-#define PGREQ_NORMAL            0
-/* Update an entry in the machine->physical mapping table. */
-#define PGREQ_MPT_UPDATE        1
-/* An extended command. */
-#define PGREQ_EXTENDED_COMMAND  2
-/* DOM0 can make entirely unchecked updates which do not affect refcnts. */
-#define PGREQ_UNCHECKED_UPDATE  3
-    unsigned long ptr, val; /* *ptr = val */
-/* Announce a new top-level page table. */
-#define PGEXT_PIN_L1_TABLE      0
-#define PGEXT_PIN_L2_TABLE      1
-#define PGEXT_PIN_L3_TABLE      2
-#define PGEXT_PIN_L4_TABLE      3
-#define PGEXT_UNPIN_TABLE       4
-#define PGEXT_NEW_BASEPTR       5
-#define PGEXT_TLB_FLUSH         6
-#define PGEXT_INVLPG            7
-#define PGEXT_CMD_MASK        255
-#define PGEXT_CMD_SHIFT         8
-} page_update_request_t;
+/* 8 entries, plus a TSS entry for each CPU (up to 32 CPUs). */
+#define FIRST_DOMAIN_GDT_ENTRY 40
+/* These are flat segments for domain bootstrap and fallback. */
+#define FLAT_RING1_CS          0x11
+#define FLAT_RING1_DS          0x19
+#define FLAT_RING3_CS          0x23
+#define FLAT_RING3_DS          0x2b
 
 
 /*
- * Segment descriptor tables.
+ * HYPERVISOR "SYSTEM CALLS"
  */
-/* 8 entries, plus a TSS entry for each CPU (up to 32 CPUs). */
-#define FIRST_DOMAIN_GDT_ENTRY  40
-/* These are flat segments for domain bootstrap and fallback. */
-#define FLAT_RING1_CS           0x11
-#define FLAT_RING1_DS           0x19
-#define FLAT_RING3_CS           0x23
-#define FLAT_RING3_DS           0x2b
-
 
 /* EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5. */
+#define __HYPERVISOR_set_trap_table       0
+#define __HYPERVISOR_pt_update            1
+#define __HYPERVISOR_console_write        2
+#define __HYPERVISOR_set_gdt              3
+#define __HYPERVISOR_stack_switch          4
+#define __HYPERVISOR_ldt_switch            5
+#define __HYPERVISOR_net_update                   6
+#define __HYPERVISOR_fpu_taskswitch       7
+#define __HYPERVISOR_yield                8
+#define __HYPERVISOR_exit                 9
+#define __HYPERVISOR_dom0_op             10
+#define __HYPERVISOR_network_op                  11
+#define __HYPERVISOR_block_io_op         12
+#define __HYPERVISOR_set_debugreg        13
+#define __HYPERVISOR_get_debugreg        14
+#define __HYPERVISOR_update_descriptor   15
+#define __HYPERVISOR_set_fast_trap       16
+#define __HYPERVISOR_dom_mem_op                  17
+#define __HYPERVISOR_multicall           18
+
+/* And the trap vector is... */
+#define TRAP_INSTR "int $0x82"
 
-#define __HYPERVISOR_set_trap_table        0
-#define __HYPERVISOR_pt_update             1
-#define __HYPERVISOR_console_write         2
-#define __HYPERVISOR_set_gdt               3
-#define __HYPERVISOR_stack_and_ldt_switch  4
-#define __HYPERVISOR_net_update            5
-#define __HYPERVISOR_fpu_taskswitch        6
-#define __HYPERVISOR_sched_op              7
-#define __HYPERVISOR_exit                  8
-#define __HYPERVISOR_dom0_op               9
-#define __HYPERVISOR_network_op           10
-#define __HYPERVISOR_block_io_op          11
-#define __HYPERVISOR_set_debugreg         12
-#define __HYPERVISOR_get_debugreg         13
-#define __HYPERVISOR_update_descriptor    14
-#define __HYPERVISOR_set_fast_trap        15
-#define __HYPERVISOR_dom_mem_op           16
 
-#define TRAP_INSTR "int $0x82"
+/*
+ * MULTICALLS
+ * 
+ * Multicalls are listed in an array, with each element being a fixed size 
+ * (BYTES_PER_MULTICALL_ENTRY). Each is of the form (op, arg1, ..., argN)
+ * where each element of the tuple is a machine word. 
+ */
+#define BYTES_PER_MULTICALL_ENTRY 32
 
 
-/* Event message note:
+/* EVENT MESSAGES
  *
  * Here, as in the interrupts to the guestos, additional network interfaces
- * are defined.  These definitions server as placeholders for the event bits,
+ * are defined.         These definitions server as placeholders for the event bits,
  * however, in the code these events will allways be referred to as shifted
  * offsets from the base NET events.
  */
@@ -113,14 +76,88 @@ typedef struct
 
 /* Bit offsets, as opposed to the above masks. */
 #define _EVENT_BLK_RESP 0
-#define _EVENT_TIMER    1
-#define _EVENT_DIE      2
-#define _EVENT_NET_TX   3
-#define _EVENT_NET_RX   4
-#define _EVENT_DEBUG    5
+#define _EVENT_TIMER   1
+#define _EVENT_DIE     2
+#define _EVENT_NET_TX  3
+#define _EVENT_NET_RX  4
+#define _EVENT_DEBUG   5
+
+
+/*
+ * Virtual addresses beyond this are not modifiable by guest OSes.
+ * The machine->physical mapping table starts at this address, read-only
+ * to all domains except DOM0.
+ */
+#define HYPERVISOR_VIRT_START (0xFC000000UL)
+#ifndef machine_to_phys_mapping
+#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
+#endif
+
+
+/*
+ * PAGE UPDATE COMMANDS AND FLAGS
+ * 
+ * PGREQ_XXX: specified in least-significant bits of 'ptr' field.
+ * All requests specify relevent PTE or PT address in 'ptr'.
+ * Normal requests specify update value in 'value'.
+ * Extended requests specify command in least 8 bits of 'value'.
+ */
+/* A normal page-table update request. */
+#define PGREQ_NORMAL           0
+/* Update an entry in the machine->physical mapping table. */
+#define PGREQ_MPT_UPDATE       1
+/* An extended command. */
+#define PGREQ_EXTENDED_COMMAND 2
+/* DOM0 can make entirely unchecked updates which do not affect refcnts. */
+#define PGREQ_UNCHECKED_UPDATE 3
+/* Announce a new top-level page table. */
+#define PGEXT_PIN_L1_TABLE     0
+#define PGEXT_PIN_L2_TABLE     1
+#define PGEXT_PIN_L3_TABLE     2
+#define PGEXT_PIN_L4_TABLE     3
+#define PGEXT_UNPIN_TABLE      4
+#define PGEXT_NEW_BASEPTR      5
+#define PGEXT_TLB_FLUSH                6
+#define PGEXT_INVLPG           7
+#define PGEXT_CMD_MASK       255
+#define PGEXT_CMD_SHIFT                8
+
 
+#ifndef __ASSEMBLY__
+
+#include "network.h"
+#include "block.h"
 
 /*
+ * Send an array of these to HYPERVISOR_set_trap_table()
+ */
+typedef struct trap_info_st
+{
+    unsigned char  vector;  /* exception/interrupt vector */
+    unsigned char  dpl;            /* privilege level            */
+    unsigned short cs;     /* code selector              */
+    unsigned long  address; /* code address              */
+} trap_info_t;
+
+/*
+ * Send an array of these to HYPERVISOR_pt_update()
+ */
+typedef struct
+{
+    unsigned long ptr, val; /* *ptr = val */
+} page_update_request_t;
+
+/*
+ * Send an array of these to HYPERVISOR_multicall()
+ */
+typedef struct
+{
+    unsigned long op;
+    unsigned long args[7];
+} multicall_entry_t;
+
+/*
+ * Xen/guestos shared data -- pointer provided in start_info.
  * NB. We expect that this struct is smaller than a page.
  */
 typedef struct shared_info_st {
@@ -150,36 +187,34 @@ typedef struct shared_info_st {
      * registers, and executing 'iret'.
      * This callback is provided with an extended stack frame, augmented
      * with saved values for segment registers %ds and %es:
-     *  %ds, %es, %eip, %cs, %eflags [, %oldesp, %oldss]
+     * %ds, %es, %eip, %cs, %eflags [, %oldesp, %oldss]
      * Code segment is the default flat selector.
      * FAULTS WHEN CALLING THIS HANDLER WILL TERMINATE THE DOMAIN!!!
      */
     unsigned long failsafe_address;
 
-       /*
-     * Time:
-     * The following abstractions are exposed: System Time, Wall Clock 
-     * Time, Domain Virtual Time. Domains can access Cycle counter time
-     * directly. 
-        * XXX RN: Need something to pass NTP scaling to GuestOS.
+    /*
+     * Time: The following abstractions are exposed: System Time, Clock Time,
+     * Domain Virtual Time. Domains can access Cycle counter time directly.
+     * XXX RN: Need something to pass NTP scaling to GuestOS.
      */
 
-       u64           cpu_freq;     /* to calculate ticks -> real time */
-
-       /* System Time */
-       long long          system_time;     /* in ns */
-       unsigned long      st_timestamp;    /* cyclecounter at last update */
+    u64                  cpu_freq;         /* to calculate ticks -> real time */
 
-       /* Wall Clock Time */
-       u32                wc_version;      /* a version number for info below */
-       long               tv_sec;          /* essentially a struct timeval */
-       long               tv_usec;
-       long long          wc_timestamp;    /* system time at last update */
+    /* System Time */
+    long long         system_time;     /* in ns */
+    unsigned long      st_timestamp;   /* cyclecounter at last update */
 
-       /* Domain Virtual Time */
-       unsigned long long domain_time;
+    /* Wall Clock Time */
+    u32                       wc_version;      /* a version number for info below */
+    long              tv_sec;          /* essentially a struct timeval */
+    long              tv_usec;
+    long long         wc_timestamp;    /* system time at last update */
+    
+    /* Domain Virtual Time */
+    unsigned long long domain_time;
        
-       /*
+    /*
      * Timeout values:
      * Allow a domain to specify a timeout value in system time and 
      * domain virtual time.
@@ -193,18 +228,20 @@ typedef struct shared_info_st {
  * NB. We expect that this struct is smaller than a page.
  */
 typedef struct start_info_st {
-    unsigned long nr_pages;       /* total pages allocated to this domain */
-    shared_info_t *shared_info;   /* VIRTUAL address of shared info struct */
-    unsigned long  pt_base;       /* VIRTUAL address of page directory */
-    unsigned long mod_start;      /* VIRTUAL address of pre-loaded module */
-    unsigned long mod_len;        /* size (bytes) of pre-loaded module */
-    net_ring_t *net_rings;        /* network rings (VIRTUAL ADDRESS) */
+    unsigned long nr_pages;      /* total pages allocated to this domain */
+    shared_info_t *shared_info;          /* VIRTUAL address of shared info struct */
+    unsigned long  pt_base;      /* VIRTUAL address of page directory */
+    unsigned long mod_start;     /* VIRTUAL address of pre-loaded module */
+    unsigned long mod_len;       /* size (bytes) of pre-loaded module */
+    net_ring_t *net_rings;       /* network rings (VIRTUAL ADDRESS) */
     int num_net_rings;
-    unsigned long blk_ring;       /* block io ring (MACHINE ADDRESS) */
-    unsigned char cmd_line[1];    /* variable-length */
+    unsigned long blk_ring;      /* block io ring (MACHINE ADDRESS) */
+    unsigned char cmd_line[1];   /* variable-length */
 } start_info_t;
 
 /* For use in guest OSes. */
 extern shared_info_t *HYPERVISOR_shared_info;
 
+#endif /* !__ASSEMBLY__ */
+
 #endif /* __HYPERVISOR_IF_H__ */
index 08cc5cb0dd4d4e81133f3eded1076724db6bbcb2..3687748a0be4e467046145aec132c5ccef569d7d 100644 (file)
 #define __GUEST_CS      0x11
 #define __GUEST_DS      0x19
 
-#define NR_syscalls 255
+#define NR_syscalls 256
 
 #define offsetof(_p,_f) ((unsigned long)&(((_p *)0)->_f))
 #define struct_cpy(_x,_y) (memcpy((_x),(_y),sizeof(*(_x))))
index c49087173f48a4f53c41a6c543a02167d80e9068..68670daa8cd63f4c1ba661bb95e610eb387f8aeb 100644 (file)
@@ -13,6 +13,9 @@
 #include <asm/system.h>
 #include <asm/ptrace.h>
 
+multicall_entry_t multicall_list[8];
+int nr_multicall_ents = 0;
+
 static unsigned long event_mask = 0;
 
 void frobb(void) {}
index a4e4cd2497f1e79f9aa333c1aaa9091ffcf12d5d..32ce1a66ab091412edfc1261c0b57083d7541347 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/i387.h>
 #include <asm/desc.h>
 #include <asm/mmu_context.h>
+#include <asm/multicall.h>
 
 #include <linux/irq.h>
 
@@ -85,7 +86,7 @@ void cpu_idle (void)
 
     while (1) {
         while (!current->need_resched)
-            HYPERVISOR_do_sched_op(NULL);
+            HYPERVISOR_yield();
         schedule();
         check_pgt_cache();
     }
@@ -334,9 +335,28 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
     struct thread_struct *prev = &prev_p->thread,
         *next = &next_p->thread;
 
-    unlazy_fpu(prev_p);
+    /*
+     * This is basically 'unlazy_fpu', except that we queue a multicall to 
+     * indicate FPU task switch, rather than synchronously trapping to Xen.
+     */
+    if ( prev_p->flags & PF_USEDFPU )
+    {
+       if ( cpu_has_fxsr )
+            asm volatile( "fxsave %0 ; fnclex"
+                          : "=m" (prev_p->thread.i387.fxsave) );
+       else
+            asm volatile( "fnsave %0 ; fwait"
+                          : "=m" (prev_p->thread.i387.fsave) );
+       prev_p->flags &= ~PF_USEDFPU;
+        queue_multicall0(__HYPERVISOR_fpu_taskswitch);
+    }
+
+    if ( next->esp0 != 0 )
+        queue_multicall2(__HYPERVISOR_stack_switch, __KERNEL_DS, next->esp0);
 
-    HYPERVISOR_stack_and_ldt_switch(__KERNEL_DS, next->esp0, 0);
+    /* EXECUTE ALL TASK SWITCH XEN SYSCALLS AT THIS POINT. */
+    execute_multicall_list();
+    sti(); /* matches 'cli' in switch_mm() */
 
     /*
      * Save away %fs and %gs. No need to save %es and %ds, as
index 1650d7028f0ba3a749a11d27181ceb9384f44ee4..00c68a836f9119568314b23aec246d4d6d5fd849 100644 (file)
@@ -967,7 +967,7 @@ void __init cpu_init (void)
         BUG();
     enter_lazy_tlb(&init_mm, current, nr);
 
-    HYPERVISOR_stack_and_ldt_switch(__KERNEL_DS, current->thread.esp0, 0);
+    HYPERVISOR_stack_switch(__KERNEL_DS, current->thread.esp0);
 
     /* Force FPU initialization. */
     current->flags &= ~PF_USEDFPU;
index 135ed5c066e7730230e80e64ed2d1c8603f9d73a..93554c34209e434346dc235483fc293a74c4780e 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/hypervisor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/multicall.h>
 
 /*
  * This suffices to protect us if we ever move to SMP domains.
@@ -85,6 +86,28 @@ static void DEBUG_disallow_pt_read(unsigned long pa)
  */
 unsigned long pt_baseptr;
 
+/*
+ * MULTICALL_flush_page_update_queue:
+ *   This is a version of the flush which queues as part of a multicall.
+ */
+void MULTICALL_flush_page_update_queue(void)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
+    if ( idx != 0 ) 
+    {
+#if PT_UPDATE_DEBUG > 1
+        printk("Flushing %d entries from pt update queue\n", idx);
+#endif
+#if PT_UPDATE_DEBUG > 0
+        DEBUG_allow_pt_reads();
+#endif
+        queue_multicall2(__HYPERVISOR_pt_update, update_queue, idx);
+        idx = 0;
+    }
+    spin_unlock_irqrestore(&update_lock, flags);
+}
+
 static inline void __flush_page_update_queue(void)
 {
 #if PT_UPDATE_DEBUG > 1
index 16f37cfe65340bdb7187e85705ff67db46cf56fd..4b9591102c820dbd1a9c585a1460d556c2ebef6f 100644 (file)
@@ -129,6 +129,7 @@ static inline int flush_page_update_queue(void)
     return idx;
 }
 #define XENO_flush_page_update_queue() (_flush_page_update_queue())
+void MULTICALL_flush_page_update_queue(void);
 
 
 /*
@@ -183,14 +184,24 @@ static inline int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
     return ret;
 }
 
-static inline int HYPERVISOR_stack_and_ldt_switch(
-    unsigned long ss, unsigned long esp, unsigned long ldts)
+static inline int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
 {
     int ret;
     __asm__ __volatile__ (
         TRAP_INSTR
-        : "=a" (ret) : "0" (__HYPERVISOR_stack_and_ldt_switch),
-        "b" (ss), "c" (esp), "d" (ldts) );
+        : "=a" (ret) : "0" (__HYPERVISOR_stack_switch),
+        "b" (ss), "c" (esp) : "memory" );
+
+    return ret;
+}
+
+static inline int HYPERVISOR_ldt_switch(unsigned long ldts)
+{
+    int ret;
+    __asm__ __volatile__ (
+        TRAP_INSTR
+        : "=a" (ret) : "0" (__HYPERVISOR_ldt_switch),
+        "b" (ldts) : "memory" );
 
     return ret;
 }
@@ -215,13 +226,12 @@ static inline int HYPERVISOR_fpu_taskswitch(void)
     return ret;
 }
 
-static inline int HYPERVISOR_do_sched_op(void *sched_op)
+static inline int HYPERVISOR_yield(void)
 {
     int ret;
     __asm__ __volatile__ (
         TRAP_INSTR
-        : "=a" (ret) : "0" (__HYPERVISOR_sched_op),
-        "b" (sched_op) );
+        : "=a" (ret) : "0" (__HYPERVISOR_yield) );
 
     return ret;
 }
@@ -296,7 +306,7 @@ static inline int HYPERVISOR_update_descriptor(
     int ret;
     __asm__ __volatile__ (
         TRAP_INSTR
-        : "=a" (ret) : "0" (__HYPERVISOR_set_gdt), 
+        : "=a" (ret) : "0" (__HYPERVISOR_update_descriptor), 
         "b" (pa), "c" (word1), "d" (word2) );
 
     return ret;
@@ -324,4 +334,15 @@ static inline int HYPERVISOR_dom_mem_op(void *dom_mem_op)
     return ret;
 }
 
+static inline int HYPERVISOR_multicall(void *call_list, int nr_calls)
+{
+    int ret;
+    __asm__ __volatile__ (
+        TRAP_INSTR
+        : "=a" (ret) : "0" (__HYPERVISOR_multicall),
+        "b" (call_list), "c" (nr_calls) : "memory" );
+
+    return ret;
+}
+
 #endif /* __HYPERVISOR_H__ */
index c5b3cdcd617fd291dd4d6ea817477a9270e6d6a4..ad07796f95f13f2e462870e51c9f295d845f37aa 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/desc.h>
 #include <asm/atomic.h>
 #include <asm/pgalloc.h>
+#include <asm/multicall.h>
 
 /*
  * possibly do the LDT unload here?
@@ -33,6 +34,7 @@ extern pgd_t *cur_pgd;
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
 {
+       cli(); /* protect flush_update_queue multicall */
        if (prev != next) {
                /* stop flush ipis for the previous mm */
                clear_bit(cpu, &prev->cpu_vm_mask);
@@ -50,7 +52,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
                /* Re-load page tables */
                cur_pgd = next->pgd;
                queue_pt_switch(__pa(cur_pgd));
-               XENO_flush_page_update_queue();
+               MULTICALL_flush_page_update_queue();
        }
 #ifdef CONFIG_SMP
        else {
@@ -70,6 +72,10 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
 }
 
 #define activate_mm(prev, next) \
-       switch_mm((prev),(next),NULL,smp_processor_id())
+do { \
+       switch_mm((prev),(next),NULL,smp_processor_id()); \
+       execute_multicall_list(); \
+       sti(); /* matches 'cli' in switch_mm() */ \
+} while ( 0 )
 
 #endif
diff --git a/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h b/xenolinux-2.4.21-pre4-sparse/include/asm-xeno/multicall.h
new file mode 100644 (file)
index 0000000..27126dc
--- /dev/null
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * multicall.h
+ */
+
+#ifndef __MULTICALL_H__
+#define __MULTICALL_H__
+
+#include <asm/hypervisor.h>
+
+extern multicall_entry_t multicall_list[];
+extern int nr_multicall_ents;
+
+static inline void queue_multicall0(unsigned long op)
+{
+    int i = nr_multicall_ents;
+    multicall_list[i].op      = op;
+    nr_multicall_ents = i+1;
+}
+
+static inline void queue_multicall1(unsigned long op, unsigned long arg1)
+{
+    int i = nr_multicall_ents;
+    multicall_list[i].op      = op;
+    multicall_list[i].args[0] = arg1;
+    nr_multicall_ents = i+1;
+}
+
+static inline void queue_multicall2(
+    unsigned long op, unsigned long arg1, unsigned long arg2)
+{
+    int i = nr_multicall_ents;
+    multicall_list[i].op      = op;
+    multicall_list[i].args[0] = arg1;
+    multicall_list[i].args[1] = arg2;
+    nr_multicall_ents = i+1;
+}
+
+static inline void execute_multicall_list(void)
+{
+    if ( unlikely(nr_multicall_ents == 0) ) return;
+    (void)HYPERVISOR_multicall(multicall_list, nr_multicall_ents);
+    nr_multicall_ents = 0;
+}
+
+#endif /* __MULTICALL_H__ */